/*
 * ADS1115.cpp
 *
 *  Created on: Jun 17, 2024
 *      Author: tangst
 */

#include "soft_i2c.h"
#include "main.h"

#define soft_i2c_high   (1)
#define soft_i2c_low    (0)

#define soft_i2c_Delay()    i2c_Delay(i2c_driver)
#define soft_i2c_SDA_H()    i2c_SDA_H(i2c_driver)
#define soft_i2c_SDA_L()    i2c_SDA_L(i2c_driver)
#define soft_i2c_SCL_H()    i2c_SCL_H(i2c_driver)
#define soft_i2c_SCL_L()    i2c_SCL_L(i2c_driver)
#define soft_i2c_SDA_Read() i2c_SDA_Read(i2c_driver)
#define soft_i2c_Start()    soft_i2c_start(i2c_driver)
#define soft_i2c_Stop()     soft_i2c_stop(i2c_driver)

#define SOFT_I2C_TimeOut  	(i2c_driver->waitTime)

static void i2c_DelayUs(soft_i2c_driver *i2c_driver,uint16_t time)
{
  i2c_driver->udelay(time);
}

static void i2c_Delay(soft_i2c_driver *i2c_driver)
{
  i2c_DelayUs(i2c_driver,i2c_driver->delay_us);
}

static void i2c_SCL_H(soft_i2c_driver *i2c_driver)
{
  i2c_driver->set_scl(soft_i2c_high);
}

static void i2c_SCL_L(soft_i2c_driver *i2c_driver)
{
  i2c_driver->set_scl(soft_i2c_low);
}

static void i2c_SDA_H(soft_i2c_driver *i2c_driver)
{
  i2c_driver->set_sda(soft_i2c_high);
}

static void i2c_SDA_L(soft_i2c_driver *i2c_driver)
{
  i2c_driver->set_sda(soft_i2c_low);
}

static int32_t i2c_SDA_Read(soft_i2c_driver *i2c_driver)
{
  uint8_t data;
  data = i2c_driver->get_sda();
  return data;
}



void soft_i2c_start(soft_i2c_driver *i2c_driver)
{
  soft_i2c_SDA_H();
  soft_i2c_SCL_H();
  soft_i2c_SDA_L();
  soft_i2c_Delay();
  soft_i2c_SCL_L();
  
}

void soft_i2c_stop(soft_i2c_driver *i2c_driver)
{
  soft_i2c_SDA_L();
  soft_i2c_SCL_H();
  soft_i2c_SDA_H();
  soft_i2c_Delay();
  soft_i2c_SCL_L();
  
} 

static void i2c_NACK(soft_i2c_driver *i2c_driver)
{
  soft_i2c_SDA_H();
  soft_i2c_SCL_H();
  soft_i2c_Delay();
  soft_i2c_SCL_L();

}

static void i2c_ACK(soft_i2c_driver *i2c_driver)
{
  soft_i2c_SDA_L();
  soft_i2c_SCL_H();
  soft_i2c_Delay();
  soft_i2c_SCL_L();
}
uint8_t soft_i2c_waitAck(soft_i2c_driver *i2c_driver)
{
  uint8_t ack;
  
  soft_i2c_SDA_H();
  soft_i2c_SCL_H();
  soft_i2c_Delay();
  ack = soft_i2c_SDA_Read();
  soft_i2c_SCL_L();
  soft_i2c_SDA_L();
  soft_i2c_Delay();

  return ack;
}

uint8_t soft_i2c_waitAckTimeOut(soft_i2c_driver *i2c_driver)
{
	uint32_t startTick;
	
	startTick = HAL_GetTick();
	
	do
	{
		if(soft_i2c_waitAck(i2c_driver) == 0)
		{
			return 0;
		}
		
	}while(HAL_GetTick() - startTick < SOFT_I2C_TimeOut);
	
	return 1;
}


void soft_i2c_Send(soft_i2c_driver *i2c_driver,uint8_t data)
{
  int i=0;
  for(i=0;i<8;i++)
  {
    soft_i2c_SCL_L();
    if(data & 0x80)
    {
      soft_i2c_SDA_H();
    }
    else
    {
      soft_i2c_SDA_L();
    }
    soft_i2c_Delay();
    soft_i2c_SCL_H();
    soft_i2c_Delay();
    data = data << 1;
  }
  soft_i2c_SCL_L();
  soft_i2c_Delay();

}
  
uint8_t soft_i2c_Receive(soft_i2c_driver *i2c_driver)
{
  int i=0;
  uint8_t data;

  soft_i2c_SCL_L();
  soft_i2c_SDA_H();
  for(i=0;i<8;i++)
  {
    data = data << 1;
    soft_i2c_SCL_H();
    soft_i2c_Delay();
    data = data + soft_i2c_SDA_Read();
    soft_i2c_SCL_L();
    soft_i2c_Delay();
  }
  i2c_ACK(i2c_driver);

  return data;
}

uint8_t soft_i2c_WriteBytes(soft_i2c_driver *i2c_driver,uint8_t data[],uint8_t size)
{
  int i=0;
  soft_i2c_start(i2c_driver);
  
  for(i=0;i<size;i++)
  {
    soft_i2c_Send(i2c_driver,data[i]);
    if(soft_i2c_waitAck(i2c_driver))
    {
      return 0;
    }
  }
  
  soft_i2c_stop(i2c_driver);
  
  return 1;
} 

uint8_t soft_i2c_WriteReg(soft_i2c_driver *i2c_driver, uint8_t reg, uint8_t reg_msb, uint8_t reg_lsb)
{
  uint8_t data[4];
  data[0] = i2c_driver->writeAddr;
  data[1] = reg;
  data[2] = reg_msb;
  data[3] = reg_lsb;
  return soft_i2c_WriteBytes(i2c_driver,data,4);
}


uint8_t soft_i2c_ReadBytes(soft_i2c_driver *i2c_driver,uint8_t reg, uint8_t data[],uint8_t size)
{
  uint32_t tick;
  soft_i2c_start(i2c_driver);
  soft_i2c_Send(i2c_driver,i2c_driver->writeAddr);
	
  if(soft_i2c_waitAckTimeOut(i2c_driver))
  {
	  return 0;
  }
  soft_i2c_Send(i2c_driver,reg);
  
  if(soft_i2c_waitAckTimeOut(i2c_driver))
  {
	  return 0;
  }
  soft_i2c_start(i2c_driver);
  soft_i2c_Send(i2c_driver,i2c_driver->writeAddr + 1);
  if(soft_i2c_waitAckTimeOut(i2c_driver))
  {
	  return 0;
  }

  for(uint8_t i=0;i<size;i++)
  {
    data[i] = soft_i2c_Receive(i2c_driver);
  }
  soft_i2c_stop(i2c_driver);
    
  return 1;
  
}

uint16_t soft_i2c_ReadReg(soft_i2c_driver *i2c_driver,uint8_t reg)
{
  uint8_t data[2];
  if(soft_i2c_ReadBytes(i2c_driver,reg,data,2) == 0)
  {
	return 0xFFFF;
  }
  return data[0]<<8 | data[1];
}

void soft_i2c_addr_set(soft_i2c_driver *i2c_driver,uint8_t writeAddr)
{
  i2c_driver->writeAddr = writeAddr;
} 


void soft_i2c_init(soft_i2c_driver *i2c_driver, 
                  void (*set_sda)(int32_t state), void (*set_scl)(int32_t state),
                  int32_t (*get_sda)(void),void (*udelay)(uint32_t us), 
				  uint8_t writeAddr, uint32_t delay_us,uint32_t waitTime)
{
  i2c_driver->set_sda = set_sda;
  i2c_driver->set_scl = set_scl;
  i2c_driver->get_sda = get_sda;
  i2c_driver->udelay = udelay;
  i2c_driver->delay_us = delay_us;
  i2c_driver->writeAddr = writeAddr;
}


